package com.hnit.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hnit.mapper.CouponGrabRecordsMapper;
import com.hnit.mapper.CouponsMapper;
import com.hnit.mapper.UserCouponsMapper;
import com.hnit.service.CouponService;
import com.hnit.web.bean.CouponGrabRecords;
import com.hnit.web.bean.Coupons;
import com.hnit.web.bean.UserCoupons;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.scheduling.annotation.Async;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.math.BigDecimal;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
 * 优惠券服务实现类
 */
@Service
@Slf4j
@Transactional
public class CouponServiceImpl implements CouponService {

    @Autowired
    private CouponsMapper couponsMapper;

    @Autowired
    private UserCouponsMapper userCouponsMapper;

    @Autowired
    private CouponGrabRecordsMapper couponGrabRecordsMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // Redis Key 前缀常量
    private static final String COUPON_STOCK_KEY = "coupon:stock:";
    private static final String COUPON_DETAIL_KEY = "coupon:detail:";
    private static final String COUPON_GRAB_LOCK_KEY = "coupon:grab:lock:";
    private static final String USER_GRAB_KEY = "coupon:user:grab:";
    private static final String USER_COUPON_STATS_KEY = "user:coupon:stats:";

    // 抢购结果枚举
    private static final int GRAB_SUCCESS = 1;
    private static final int GRAB_FAIL_NO_STOCK = 2;
    private static final int GRAB_FAIL_DUPLICATE = 3;
    private static final int GRAB_FAIL_NOT_STARTED = 4;
    private static final int GRAB_FAIL_ENDED = 5;
    private static final int GRAB_FAIL_USER_LIMIT = 6;

    @Override
    public IPage<Coupons> getCouponsList(Integer page, Integer size, Integer status) {
        Page<Coupons> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Coupons> wrapper = new LambdaQueryWrapper<>();

        LocalDateTime now = LocalDateTime.now();

        // 根据状态筛选
        if (status != null) {
            switch (status) {
                case 1: // 进行中
                    wrapper.eq(Coupons::getCouponStatus, 1)
                           .le(Coupons::getStartTime, now)
                           .ge(Coupons::getEndTime, now)
                           .gt(Coupons::getRemainingCount, 0);
                    break;
                case 2: // 即将开始
                    wrapper.eq(Coupons::getCouponStatus, 1)
                           .gt(Coupons::getStartTime, now);
                    break;
                case 3: // 已结束
                    wrapper.and(w -> w.eq(Coupons::getCouponStatus, 0)
                                   .or().lt(Coupons::getEndTime, now)
                                   .or().eq(Coupons::getRemainingCount, 0));
                    break;
                default:
                    wrapper.eq(Coupons::getCouponStatus, 1);
                    break;
            }
        } else {
            wrapper.eq(Coupons::getCouponStatus, 1);
        }

        wrapper.orderByDesc(Coupons::getCreatedTime);

        Page<Coupons> result = couponsMapper.selectPage(pageParam, wrapper);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean grabCoupon(Long userId, Long couponId, HttpServletRequest request) throws Exception {
        String lockKey = COUPON_GRAB_LOCK_KEY + couponId + ":" + userId;
        String grabKey = USER_GRAB_KEY + couponId + ":" + userId;
        String stockKey = COUPON_STOCK_KEY + couponId;

        // 获取IP地址
//        String ipAddress = getClientIpAddress(request);
//        String userAgent = request.getHeader("User-Agent");
        String ipAddress = request != null ? getClientIpAddress(request) : "unknown";
        String userAgent = request != null ? request.getHeader("User-Agent") : "unknown";

        try {
            // 1. 分布式锁防重复提交（10秒超时）
            Boolean lockResult = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "1", Duration.ofSeconds(10));
            if (!lockResult) {
                log.warn("用户{}重复抢购优惠券{}", userId, couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_DUPLICATE, "重复抢购", ipAddress, userAgent);
                throw new Exception("请勿重复提交");
            }

            // 2. 检查是否已经抢过（防止缓存失效后重复抢购）
            if (Boolean.TRUE.equals(redisTemplate.hasKey(grabKey))) {
                log.warn("用户{}已抢购过优惠券{}", userId, couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_DUPLICATE, "已领取过", ipAddress, userAgent);
                throw new Exception("您已领取过该优惠券");
            }

            // 3. 检查优惠券状态和时间
            Coupons coupon = getCouponFromCacheOrDB(couponId);
            if (coupon == null || coupon.getCouponStatus() != 1) {
                log.warn("优惠券{}不存在或已下架", couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_NOT_STARTED, "优惠券不存在或已下架", ipAddress, userAgent);
                throw new Exception("优惠券不存在或已下架");
            }

            LocalDateTime now = LocalDateTime.now();
            if (now.isBefore(coupon.getStartTime())) {
                log.warn("优惠券{}活动未开始", couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_NOT_STARTED, "活动未开始", ipAddress, userAgent);
                throw new Exception("活动未开始");
            }
            if (now.isAfter(coupon.getEndTime())) {
                log.warn("优惠券{}活动已结束", couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_ENDED, "活动已结束", ipAddress, userAgent);
                throw new Exception("活动已结束");
            }

            // 4. 检查用户领取限制
            Long userCouponCount = getUserCouponCount(userId, couponId);
            if (userCouponCount >= coupon.getUserLimit()) {
                log.warn("用户{}已达到优惠券{}领取上限", userId, couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_USER_LIMIT, "已达到领取上限", ipAddress, userAgent);
                throw new Exception("您已达到领取上限");
            }

            // 5. Redis预扣库存
            Long remainingStock = redisTemplate.opsForValue().decrement(stockKey);
            if (remainingStock < 0) {
                // 库存不足，回滚Redis
                redisTemplate.opsForValue().increment(stockKey);
                log.warn("优惠券{}库存不足", couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_NO_STOCK, "库存不足", ipAddress, userAgent);
                throw new Exception("优惠券已抢完");
            }

            // 6. 生成用户优惠券记录
            UserCoupons userCoupon = createUserCoupon(userId, coupon, now);
            int insertResult = userCouponsMapper.insert(userCoupon);

            if (insertResult <= 0) {
                // 插入失败，回滚库存
                redisTemplate.opsForValue().increment(stockKey);
                log.error("用户优惠券记录插入失败，用户:{}, 优惠券:{}", userId, couponId);
                recordGrabLog(userId, couponId, GRAB_FAIL_DUPLICATE, "数据库插入失败", ipAddress, userAgent);
                throw new Exception("抢购失败，请重试");
            }

            // 7. 设置抢购成功标记（24小时过期）
            redisTemplate.opsForValue().set(grabKey, "1", Duration.ofDays(1));

            // 8. 异步更新数据库库存
            updateCouponStockAsync(couponId);

            // 9. 清除用户优惠券统计缓存
            redisTemplate.delete(USER_COUPON_STATS_KEY + userId);

            // 10. 记录抢购成功日志
            recordGrabLog(userId, couponId, GRAB_SUCCESS, "抢购成功", ipAddress, userAgent);

            log.info("用户{}成功抢购优惠券{}", userId, couponId);
            return true;

        } catch (Exception e) {
            log.error("抢券异常，用户:{}, 优惠券:{}", userId, couponId, e);
            // 确保在异常情况下回滚Redis库存
            try {
                redisTemplate.opsForValue().increment(stockKey);
            } catch (Exception rollbackException) {
                log.error("回滚Redis库存失败", rollbackException);
            }
            throw e;
        } finally {
            // 释放分布式锁
            redisTemplate.delete(lockKey);
        }
    }

    @Override
    public IPage<UserCoupons> getUserCoupons(Long userId, Integer page, Integer size, Integer status) {
        Page<UserCoupons> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(UserCoupons::getUserId, userId);

        if (status != null) {
            wrapper.eq(UserCoupons::getCouponStatus, status);
        }

        wrapper.orderByDesc(UserCoupons::getReceiveTime);

        Page<UserCoupons> result = userCouponsMapper.selectPage(pageParam, wrapper);

        // 关联查询优惠券详情
        for (UserCoupons userCoupon : result.getRecords()) {
            Coupons coupon = couponsMapper.selectById(userCoupon.getCouponId());
            userCoupon.setCoupon(coupon);
        }

        return result;
    }

    @Override
    public boolean checkUserCanGrab(Long userId, Long couponId) {
        try {
            // 1. 检查Redis缓存中是否已抢购
            String grabKey = USER_GRAB_KEY + couponId + ":" + userId;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(grabKey))) {
                return false;
            }

            // 2. 检查数据库中是否已抢购
            Long userCouponCount = getUserCouponCount(userId, couponId);
            if (userCouponCount > 0) {
                // 补充Redis缓存
                redisTemplate.opsForValue().set(grabKey, "1", Duration.ofDays(1));
                return false;
            }

            // 3. 检查优惠券状态
            Coupons coupon = getCouponFromCacheOrDB(couponId);
            if (coupon == null || coupon.getCouponStatus() != 1) {
                return false;
            }

            LocalDateTime now = LocalDateTime.now();
            if (now.isBefore(coupon.getStartTime()) || now.isAfter(coupon.getEndTime())) {
                return false;
            }

            // 4. 检查库存
            String stockKey = COUPON_STOCK_KEY + couponId;
            Object stockObj = redisTemplate.opsForValue().get(stockKey);
            if (stockObj != null) {
                Integer stock = (Integer) stockObj;
                return stock > 0;
            }

            return coupon.getRemainingCount() > 0;

        } catch (Exception e) {
            log.error("检查用户抢券资格异常，用户:{}, 优惠券:{}", userId, couponId, e);
            return false;
        }
    }

    @Override
    public Coupons getCouponDetail(Long couponId) {
        return getCouponFromCacheOrDB(couponId);
    }

    @Override
    public List<UserCoupons> getAvailableCouponsForOrder(Long userId, Double totalAmount, List<Long> productIds) {
        BigDecimal orderAmount = BigDecimal.valueOf(totalAmount);

        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getUserId, userId)
               .eq(UserCoupons::getCouponStatus, 1) // 未使用
               .gt(UserCoupons::getExpireTime, LocalDateTime.now()); // 未过期

        List<UserCoupons> userCoupons = userCouponsMapper.selectList(wrapper);

        // 过滤可用优惠券
        return userCoupons.stream()
                .filter(userCoupon -> {
                    Coupons coupon = couponsMapper.selectById(userCoupon.getCouponId());
                    userCoupon.setCoupon(coupon);

                    if (coupon == null) {
                        return false;
                    }

                    // 检查门槛金额
                    if (coupon.getThresholdAmount() != null &&
                        orderAmount.compareTo(coupon.getThresholdAmount()) < 0) {
                        return false;
                    }

                    // 这里可以添加更多业务规则，比如适用商品范围等
                    return true;
                })
                .collect(java.util.stream.Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean useCoupon(Long userId, String couponCode, Long orderId) {
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getUserId, userId)
               .eq(UserCoupons::getCouponCode, couponCode)
               .eq(UserCoupons::getCouponStatus, 1); // 未使用

        UserCoupons userCoupon = userCouponsMapper.selectOne(wrapper);
        if (userCoupon == null) {
            log.warn("优惠券不存在或已使用，用户:{}, 券码:{}", userId, couponCode);
            return false;
        }

        // 检查是否过期
        if (userCoupon.getExpireTime().isBefore(LocalDateTime.now())) {
            log.warn("优惠券已过期，用户:{}, 券码:{}", userId, couponCode);
            return false;
        }

        // 更新使用状态
        userCoupon.setCouponStatus(2); // 已使用
        userCoupon.setUseTime(LocalDateTime.now());
        userCoupon.setOrderId(orderId);

        int updateResult = userCouponsMapper.updateById(userCoupon);
        if (updateResult > 0) {
            // 清除用户优惠券统计缓存
            redisTemplate.delete(USER_COUPON_STATS_KEY + userId);
            log.info("优惠券使用成功，用户:{}, 券码:{}, 订单:{}", userId, couponCode, orderId);
            return true;
        }

        return false;
    }

    @Override
    public int[] getUserCouponStats(Long userId) {
        String cacheKey = USER_COUPON_STATS_KEY + userId;

        // 先尝试从Redis获取
        try {
            Object cachedStats = redisTemplate.opsForValue().get(cacheKey);
            if (cachedStats != null) {
                return (int[]) cachedStats;
            }
        } catch (Exception e) {
            log.warn("Redis缓存类型转换失败，清除缓存并重新查询，cacheKey: {}", cacheKey, e);
            // 删除有问题的缓存
            redisTemplate.delete(cacheKey);
        }

        // 从数据库查询
        LocalDateTime now = LocalDateTime.now();

        // 未使用数量
        LambdaQueryWrapper<UserCoupons> unusedWrapper = new LambdaQueryWrapper<>();
        unusedWrapper.eq(UserCoupons::getUserId, userId)
                     .eq(UserCoupons::getCouponStatus, 1)
                     .gt(UserCoupons::getExpireTime, now);
        int unusedCount = Math.toIntExact(userCouponsMapper.selectCount(unusedWrapper));

        // 已使用数量
        LambdaQueryWrapper<UserCoupons> usedWrapper = new LambdaQueryWrapper<>();
        usedWrapper.eq(UserCoupons::getUserId, userId)
                   .eq(UserCoupons::getCouponStatus, 2);
        int usedCount = Math.toIntExact(userCouponsMapper.selectCount(usedWrapper));

        // 已过期数量
        LambdaQueryWrapper<UserCoupons> expiredWrapper = new LambdaQueryWrapper<>();
        expiredWrapper.eq(UserCoupons::getUserId, userId)
                      .and(w -> w.eq(UserCoupons::getCouponStatus, 3)
                               .or().and(subW -> subW.eq(UserCoupons::getCouponStatus, 1)
                                                   .lt(UserCoupons::getExpireTime, now)));
        int expiredCount = Math.toIntExact(userCouponsMapper.selectCount(expiredWrapper));

        int[] stats = {unusedCount, usedCount, expiredCount};

        // 缓存5分钟
        redisTemplate.opsForValue().set(cacheKey, stats, Duration.ofMinutes(5));

        return stats;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateExpiredCoupons() {
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getCouponStatus, 1) // 未使用
               .lt(UserCoupons::getExpireTime, LocalDateTime.now()); // 已过期

        UserCoupons updateCoupon = new UserCoupons();
        updateCoupon.setCouponStatus(3); // 已过期

        int updateCount = userCouponsMapper.update(updateCoupon, wrapper);

        if (updateCount > 0) {
            log.info("批量更新过期优惠券数量: {}", updateCount);
        }

        return updateCount;
    }

    @Override
    public void warmUpCouponCache(Long couponId) {
        try {
            Coupons coupon = couponsMapper.selectById(couponId);
            if (coupon != null) {
                // 缓存优惠券详情（1小时）
                String detailKey = COUPON_DETAIL_KEY + couponId;
                redisTemplate.opsForValue().set(detailKey, coupon, Duration.ofHours(1));

                // 缓存库存
                String stockKey = COUPON_STOCK_KEY + couponId;
                redisTemplate.opsForValue().set(stockKey, coupon.getRemainingCount());

                log.info("预热优惠券缓存成功，优惠券ID: {}", couponId);
            }
        } catch (Exception e) {
            log.error("预热优惠券缓存失败，优惠券ID: {}", couponId, e);
        }
    }

    @Override
    @Async
    public void syncStockToDatabase(Long couponId) {
        try {
            String stockKey = COUPON_STOCK_KEY + couponId;
            Object stockObj = redisTemplate.opsForValue().get(stockKey);

            if (stockObj != null) {
                Integer redisStock = (Integer) stockObj;

                Coupons coupon = new Coupons();
                coupon.setCouponId(couponId);
                coupon.setRemainingCount(redisStock);
                coupon.setUpdatedTime(LocalDateTime.now());

                couponsMapper.updateById(coupon);
                log.info("同步Redis库存到数据库成功，优惠券:{}, 库存:{}", couponId, redisStock);
            }
        } catch (Exception e) {
            log.error("同步Redis库存到数据库失败，优惠券ID: {}", couponId, e);
        }
    }

    @Override
    public IPage<Coupons> getAllCouponsWithConditions(
            Integer page,
            Integer size,
            String couponName,
            Integer couponType,
            Integer couponStatus,
            BigDecimal minAmount,
            BigDecimal maxAmount,
            String startTime,
            String endTime,
            String sortBy,
            String sortOrder) {

        // 创建分页对象
        Page<Coupons> pageObj = new Page<>(page, size);

        // 构建查询条件
        QueryWrapper<Coupons> queryWrapper = new QueryWrapper<>();

        // 1. 优惠券名称模糊查询
        if (StringUtils.hasText(couponName)) {
            queryWrapper.like("couponName", couponName.trim());
        }

        // 2. 优惠券类型精确查询
        if (couponType != null) {
            queryWrapper.eq("couponType", couponType);
        }

        // 3. 优惠券状态查询
        if (couponStatus != null) {
            queryWrapper.eq("couponStatus", couponStatus);
        }

        // 4. 金额范围查询（基于门槛金额或优惠金额）

        if (minAmount != null&& (minAmount.compareTo(BigDecimal.ZERO) > 0) || maxAmount != null && maxAmount.compareTo(BigDecimal.ZERO)>0) {
            // 根据优惠券类型判断查询哪个金额字段
            if (minAmount != null) {
                queryWrapper.and(wrapper -> wrapper
                        .ge("thresholdAmount", minAmount)
                        .or()
                        .ge("discountAmount", minAmount)
                );
            }
            if (maxAmount != null) {
                queryWrapper.and(wrapper -> wrapper
                        .le("thresholdAmount", maxAmount)
                        .or()
                        .le("discountAmount", maxAmount)
                );
            }
        }

        // 5. 时间范围查询
        if (StringUtils.hasText(startTime)) {
            try {
                LocalDateTime startDateTime = LocalDateTime.parse(startTime + " 00:00:00",
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                queryWrapper.ge("startTime", startDateTime);
            } catch (Exception e) {
                // 时间格式错误，忽略该条件
            }
        }

        if (StringUtils.hasText(endTime)) {
            try {
                LocalDateTime endDateTime = LocalDateTime.parse(endTime + " 23:59:59",
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                queryWrapper.le("endTime", endDateTime);
            } catch (Exception e) {
                // 时间格式错误，忽略该条件
            }
        }

        // 6. 排序处理
        if (StringUtils.hasText(sortBy)) {
            String orderColumn = convertSortField(sortBy);
            if (StringUtils.hasText(orderColumn)) {
                boolean isAsc = !"desc".equalsIgnoreCase(sortOrder);
                if (isAsc) {
                    queryWrapper.orderByAsc(orderColumn);
                } else {
                    queryWrapper.orderByDesc(orderColumn);
                }
            }
        } else {
            // 默认按创建时间倒序排列
            queryWrapper.orderByDesc("createdTime");
        }

        // 执行分页查询
        return couponsMapper.selectPage(pageObj, queryWrapper);
    }

    @Override
    public void createCoupon(Coupons coupon) {
        couponsMapper.insert(coupon);
    }

    /**
     * 转换前端排序字段到数据库字段
     * @param sortBy 前端排序字段
     * @return 数据库字段名
     */
    private String convertSortField(String sortBy) {
        switch (sortBy) {
            case "createTime":
                return "createdTime";
            case "amount":
                return "discountAmount";
            case "endTime":
                return "endTime";
            case "startTime":
                return "startTime";
            case "couponName":
                return "couponName";
            case "thresholdAmount":
                return "thresholdAmount";
            default:
                return null;
        }
    }

    // ========== 私有方法 ==========

    /**
     * 从缓存或数据库获取优惠券信息
     */
    private Coupons getCouponFromCacheOrDB(Long couponId) {
        String detailKey = COUPON_DETAIL_KEY + couponId;

        // 先从Redis获取
        Object cachedCoupon = redisTemplate.opsForValue().get(detailKey);
        if (cachedCoupon != null) {
            return (Coupons) cachedCoupon;
        }

        // 从数据库获取并缓存
        Coupons coupon = couponsMapper.selectById(couponId);
        if (coupon != null) {
            redisTemplate.opsForValue().set(detailKey, coupon, Duration.ofMinutes(30));
        }

        return coupon;
    }

    /**
     * 获取用户已领取的优惠券数量
     */
    private Long getUserCouponCount(Long userId, Long couponId) {
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getUserId, userId)
               .eq(UserCoupons::getCouponId, couponId);
        return userCouponsMapper.selectCount(wrapper);
    }

    /**
     * 创建用户优惠券记录
     */
    private UserCoupons createUserCoupon(Long userId, Coupons coupon, LocalDateTime now) {
        UserCoupons userCoupon = new UserCoupons();
        userCoupon.setUserId(userId);
        userCoupon.setCouponId(coupon.getCouponId());
        userCoupon.setCouponCode(generateCouponCode());
        userCoupon.setCouponStatus(1); // 未使用
        userCoupon.setReceiveTime(now);
        userCoupon.setExpireTime(now.plusDays(coupon.getValidDays()));
        return userCoupon;
    }

    /**
     * 生成唯一优惠券码
     */
    private String generateCouponCode() {
        return "CPN" + System.currentTimeMillis() +
               String.format("%04d", (int)(Math.random() * 10000));
    }

    /**
     * 异步更新数据库库存
     */
    @Async
    public void updateCouponStockAsync(Long couponId) {
        try {
            // 使用乐观锁更新库存
            Coupons coupon = couponsMapper.selectById(couponId);
            if (coupon != null && coupon.getRemainingCount() > 0) {
                coupon.setRemainingCount(coupon.getRemainingCount() - 1);
                coupon.setUpdatedTime(LocalDateTime.now());
                couponsMapper.updateById(coupon);
            }
        } catch (Exception e) {
            log.error("异步更新数据库库存失败，优惠券ID: {}", couponId, e);
        }
    }

    /**
     * 记录抢购日志
     */
    @Async
    public void recordGrabLog(Long userId, Long couponId, Integer result, String reason, String ipAddress, String userAgent) {
        try {
            CouponGrabRecords record = new CouponGrabRecords();
            record.setUserId(userId);
            record.setCouponId(couponId);
            record.setGrabTime(LocalDateTime.now());
            record.setGrabResult(result);
            record.setFailReason(reason);
            record.setIpAddress(ipAddress);
            record.setUserAgent(userAgent);

            couponGrabRecordsMapper.insert(record);
        } catch (Exception e) {
            log.error("记录抢购日志失败", e);
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xip = request.getHeader("X-Real-IP");
        String xfor = request.getHeader("X-Forwarded-For");
        if (xfor != null && !xfor.isEmpty() && !"unknown".equalsIgnoreCase(xfor)) {
            int index = xfor.indexOf(',');
            if (index != -1) {
                return xfor.substring(0, index);
            } else {
                return xfor;
            }
        }
        if (xip != null && !xip.isEmpty() && !"unknown".equalsIgnoreCase(xip)) {
            return xip;
        }
        return request.getRemoteAddr();
    }
}
